#include <stdio.h>
#include <stdlib.h>

#ifdef __APPLE__
#include <OpenGL/OpenGL.h>
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif

#include "imagehandler.h"

//Getters
char* Image::Pixels() {
	return pixels;
}

int Image::Width() {
	return width;
}

int Image::Height() {
	return height;
}

int Image::Type() {
	return type;
}

//Setters
void Image::Pixels(char* px) {
	pixels = px;
}
	
void Image::Width(int w) {
	width = w;
}

void Image::Height(int h) {
	height = h;
}

void Image::Type(int tp) {
	type = tp;
}

//Constructor
Image::Image(char* filename) {
	FILE * inputimage=NULL;
	char id[2]; int offsetToData; int padding; int widthInBytes;
	
	inputimage = fopen(filename, "rb");
		
	if (inputimage==NULL) {
		printf("Error in input");
		exit(1);
	}
	
	fread(id, sizeof(char), 2, inputimage); //verifies if this image is a bitmap
	
	if ((id[0]=='B')&&(id[1]=='M'))
		type = bmp;
	else
		printf("File type not supported");
	
	//Getting the dimensions of the image
	fseek(inputimage, 18, SEEK_SET); //Sets the pointer to beginning of image size info
	
	fread(&width, sizeof(int), 1, inputimage);
	fread(&height, sizeof(int), 1, inputimage);
	
	//Getting the bitsPerPixel value
	fseek(inputimage, 28, SEEK_SET);
	
	fread(&bitsPerPixel, sizeof(short), 1, inputimage);
	
	//Getting the pixel data
	fseek(inputimage, 10, SEEK_SET); //sets the pointer to 10 bits after the beginning of the file
	fread(&offsetToData, sizeof(int), 1, inputimage); //Gets the offset for start of pixel data
	
	widthInBytes = width*bitsPerPixel/8.0;
	pixels = new char [widthInBytes*height]; //alloc the pixel string of chars
	
	//Check for padding
	padding = (widthInBytes%4);
	
	
	if (height<0) { //Data is stored in big-endian form
		fseek(inputimage, offsetToData, SEEK_SET);
		
		for (int i=0; i<height; i++) {
			for (int j=0; j<width; j++) { 
				fread(pixels, sizeof(char), 3, inputimage); //Only deals with 24-bit BMP
			}
			
			fseek(inputimage, offsetToData+i*widthInBytes+padding, SEEK_SET);
		}
	}
	else { //Little-endian form
		fseek(inputimage, offsetToData, SEEK_SET);
		int vect=0;
		
		for (int i=0; i<height; i++) {
			for (int j=0; j<width; j++) {
				fread(&pixels[vect+2], sizeof(char), 1, inputimage);
				fread(&pixels[vect+1], sizeof(char), 1, inputimage);
				fread(&pixels[vect], sizeof(char), 1, inputimage);
				vect+=3;
			}
		
			fseek(inputimage, offsetToData+i*widthInBytes+padding, SEEK_SET);
		}
	}
	
	fclose(inputimage);
}

//Destructor
Image::~Image() {
	delete pixels;
}

GLuint Image::loadTexture() { //Transforms the image into texture
	GLuint textureId;
	glGenTextures(1, &textureId); //Make room for our texture
	glBindTexture(GL_TEXTURE_2D, textureId); //Tell OpenGL which texture to edit
	//Map the image to the texture
	glTexImage2D(GL_TEXTURE_2D,                //Always GL_TEXTURE_2D
				 0,                            //0 for now
				 GL_RGB,                       //Format OpenGL uses for image
				 width, height,  //Width and height
				 0,                            //The border of the image
				 GL_RGB, //GL_RGB, because pixels are stored in RGB format
				 GL_UNSIGNED_BYTE, //GL_UNSIGNED_BYTE, because pixels are stored
				 //as unsigned numbers
				 pixels);               //The actual pixel data
	return textureId; //Returns the id of the texture
}